/*
 * MIT License
 * 
 * Copyright (c) 2017 wen.gu <454727014@qq.com>
 * 
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 * 
 * The above copyright notice and this permission notice shall be included in all
 * copies or substantial portions of the Software.
 * 
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/*****************************************************************************
 * Name:general_macro.h
 *
 * Purpose:standard header,and unified mcaro define
 *
 * Developer:
 *     w.gu,2015-12-15
 * Warning:
 *     these macro cann't have any ++, -- in parameter.
 *
 *****************************************************************************/

#ifndef __GENERAL_MACRO_H__
#define __GENERAL_MACRO_H__

#include <assert.h>
#include "general_type.h"

/***************************************************************************
 *math macro define
 ***************************************************************************/
#define GABS(a)             (((a) > 0) ? (a) : -(a))
#define GMIN(a, b)          ((a) < (b) ? (a) : (b))
#define GMAX(a, b)          ((a) > (b) ? (a) : (b))

/**make sure the range of v, between 'min' and 'max' */
#define GCLIP(v, min, max) GMIN(GMAX(v, min), max)

//fourcc macro define
#define GFCC(a, b, c, d)    (((GU32)a) | (((GU32)b) << 8) | (((GU32)c) << 16) | (((GU32)d) << 24))


/***************************************************************************
 *bytes operation macro define
 ***************************************************************************/
// read 2 bytes data by big endian 
#define GRB2(a)  ((GU16)((((GU08*)(a))[0] <<  8) | ((GU08*)(a))[1]))
// read 3 bytes data by big endian 
#define GRB3(a)  ((GU32)((((GU08*)(a))[0] <<  16) | (((GU08*)(a))[1] << 8) | ((GU08*)(a))[2]))
// read 4 bytes data by big endian 
#define GRB4(a)  ((GU32)((((GU08*)(a))[0] << 24) | (((GU08*)(a))[1] << 16) |  \
		        (((GU08*)(a))[2] <<  8) | ((GU08*)(a))[3]))
// read 8 bytes data by big endian 
#define GRB8(a)  ((((GU64)((GU08*)(a))[0]) << 56) | (((GU64)((GU08*)(a))[1]) << 48) |  \
		        (((GU64)((GU08*)(a))[2]) << 40)  | (((GU64)((GU08*)(a))[3]) << 32) |  \
				(((GU64)((GU08*)(a))[4]) << 24)  | (((GU64)((GU08*)(a))[5]) << 16) |  \
				(((GU64)((GU08*)(a))[6]) <<  8)  | (GU64)(((GU08*)(a))[7]))


// read 2 bytes data by little endian
#define GRL2(a)  ((GU16)(((GU08*)(a))[0] | (((GU08*)(a))[1] << 8)))
// read 3 bytes data by little endian
#define GRL3(a)  ((GU32)(((GU08*)(a))[0] | (((GU08*)(a))[1] << 8) | (((GU08*)(a))[2] <<  16)))
// read 4 bytes data by little endian
#define GRL4(a)  ((GU32)(((GU08*)(a))[0] | (((GU08*)(a))[1] <<  8) |  \
		        (((GU08*)(a))[2] << 16) | (((GU08*)(a))[3] << 24)))
// read 8 bytes data by little endian
#define GRL8(a)  (((GU64)((GU08*)(a))[0]) | (((GU64)((GU08*)(a))[1]) << 8) |  \
		        (((GU64)((GU08*)(a))[2]) << 16) | (((GU64)((GU08*)(a))[3]) << 24) |  \
				(((GU64)((GU08*)(a))[4]) << 32) | (((GU64)((GU08*)(a))[5]) << 40) |  \
				(((GU64)((GU08*)(a))[6]) << 48) | (((GU64)((GU08*)(a))[7]) << 56))


// write 2 bytes data as big endian
#define GWB2(a, b)  do{((GU08*)(a))[0] = (b) >> 8;((GU08*)(a))[1] = (b);}while(0)
// write 4 bytes data as big endian
#define GWB4(a, b)  do{((GU08*)(a))[0] = (b >> 24);((GU08*)(a))[1] = (b >> 16);  \
					((GU08*)(a))[2] = (b >> 8);((GU08*)(a))[3] = (b);}while(0)

// write 2 bytes data as little endian
#define GWL2(a, b)  do{((GU08*)(a))[0] = (b);((GU08*)(a))[1] = (b >> 8);}while(0)
// write 4 bytes data as little endian
#define GWL4(a, b)  do{((GU08*)(a))[0] = (b);((GU08*)(a))[1] = (b >> 8);       \
					((GU08*)(a))[2] = (b >> 16);((GU08*)(a))[3] = (b >> 24);}while(0)

// swap 2 bytes integer 
#define GSWAP2(a)  ((GU16)((((a) & 0xff00) >> 8) | (((a) & 0xff) << 8)))
// swap 4 bytes integer 				
#define GSWAP4(a)  ((((a) & 0xff) << 24) | (((a) & 0xff00) << 8) | \
	              (((a) >> 8) & 0xff00) | (((a) >> 24) & 0xff))

//write little endian data to a ptr unit in bytes
#define GPWL1(p, b) (*(p)++ = (GU08)(b))

#define GPWL2(p, var) do{*(p)++ = (GU08)((var)>>0);*(p)++ = (GU08)((var)>>8);} while(0) 

#define GPWL4(p, var) do{*(p)++ = (GU08)((var)>>0);*(p)++ = (GU08)((var)>>8);  \
						*(p)++ = (GU08)((var)>>16);*(p)++ = (GU08)((var)>>24);}while(0) 

//write big endian data to a ptr unit in bytes
#define GPWB1(p, b) (*(p)++ = (GU08)(b)) 

#define GPWB2(p, var) do{*(p)++ = (GU08)((var)>>8);*(p)++ = (GU08)((var)>>0);}while(0)

#define GPWB4(p, var) do{*(p)++ = (GU08)((var)>>24);*(p)++ = (GU08)((var)>>16);  \
                        *(p)++ = (GU08)((var) >> 8); *(p)++ = (GU08)((var) >> 0);}while (0)

//write n bytes data to a ptr 
#define GPWN(p, buf, n) do{memcpy((p), (buf), (n)); ((GU08 *)(p)) += (n);}while(0)

/***************************************************************************
 *array operation macro define
 ***************************************************************************/
//get array element counts
#define GALEN(a) (sizeof(a) / sizeof((a)[0]))

/***************************************************************************
 * for normal variable value
 ***************************************************************************/
//set value to variable
#define GVSET(var, value) ((var) = (value))

//judagement var1 and var2 is equal
#define GVEQ(var1, var2) ((var1) == (var2))

//judagement var1 and var2 is not equal
#define GVNE(var1, var2) ((var1) != (var2))

//judagement var1 is less than(or equal) var2 
#define GVLE(var1, var2) ((var1) <= (var2))

//judagement var1 is less than var2
#define GVLT(var1, var2) ((var1) < (var2))

//judagement var1 is greater than(or equal) var2
#define GVGE(var1, var2) ((var1) >= (var2))

//judagement var1 is greater than var2
#define GVGT(var1, var2) ((var1) > (var2))

/***************************************************************************
 * structure operation macro
 ***************************************************************************/
//initialize structure
#define GSTRUCT_INIT(a)  memset(&(a), 0, sizeof(a))
//initialize structure with ptr
#define GSTRUCT_PTR_INIT(p) memset(p, 0, sizeof(*(p)))


/***************************************************************************
* assert operation macro
***************************************************************************/
//if not equal then do assert break;
#define GCEQ(val1, val2) assert(GVEQ(val1, val2))
#define GCLT(val1, val2) assert(GVLT(val1, val2))
#define GCHECK(val)      assert(val)

/***************************************************************************
* Branch prediction macro
***************************************************************************/
#ifdef __GNUC__
#define GLIKELY(p)   __builtin_expect(!!(p), 1)
#define GUNLIKELY(p) __builtin_expect(!!(p), 0)
#else
#define GLIKELY(p)   (!!(p))
#define GUNLIKELY(p) (!!(p))
#endif

#endif //end of __GENERAL_MACRO_H__
 
